#include "StdAfx.h"
#include "LayoutListItem.h"
#include "Language.h"
#include "Theme.h"
#include "Util.h"
#include "ListSelectorDlg.h"
#include "PickPathDlg.h"
#include <atldlgs.h>
#include "TextInputDlg.h"
#include "IntInputDlg.h"

bool CLayoutListItem::Load(CBaseReader& r)
{
  m_text = CLanguage::Get(m_name);
  return true;
}

void CLayoutListItemText::Draw(HDC hdc, const RECT& rc) const
{
  DrawBackground(hdc, rc);

  int space = (rc.bottom-rc.top - CTheme::fntLayoutLblSmall.size - CTheme::fntLayoutText.size) / 3;
  space = max(0, space);
  CRect rctxt = rc;
  rctxt.top += space;
  rctxt.bottom = rctxt.top + CTheme::fntLayoutLblSmall.size;
  DrawText(hdc, rctxt, m_text, DT_DEFAULT, CTheme::fntLayoutLblSmall, CTheme::clrLayoutLbl, CTheme::clrLayoutLblSel);

  rctxt.top = rctxt.bottom + space;
  rctxt.bottom = rc.bottom - space;
  DrawText(hdc, rctxt, m_value, DT_MULTILINE, CTheme::fntLayoutText);
}

bool CLayoutListItemText::DoEditDlg(HWND hParent, int vKey)
{
  HWND hParentWnd = ::GetParent(hParent);

  CRect rc = GetRect();
  int space = (rc.Height() - CTheme::fntLayoutLblSmall.size - CTheme::fntLayoutText.size) / 3;
  space = max(0, space);
  rc.SetRect(0, space + CTheme::fntLayoutLblSmall.size, rc.Width(), rc.Height());

  CListTextInputDlg dlg(this, rc);
  if (!dlg.Create(hParentWnd))
    return false;

  dlg.SetText(m_value);
  dlg.SetStartKey(vKey);

  if (pList)
  {
    pList->EnableWindow(FALSE);
    pList->Redraw();
  }

  int res = dlg.DoModal();

  if (pList)
  {
    pList->EnableWindow(TRUE);
    pList->Redraw();
  }

  if (res == IDOK)
  {
    SetValue(dlg.GetText());
  }

  return true;
}

bool CLayoutListItemText::OnKeyDown(HWND hParent, int vKey)
{
  switch (vKey)
  {
  case VK_T0:
  case VK_T1:
  case VK_T2:
  case VK_T3:
  case VK_T4:
  case VK_T5:
  case VK_T6:
  case VK_T7:
  case VK_T8:
  case VK_T9:
    DoEditDlg(hParent, vKey);
    return true;
  }
  return false;
}

void CLayoutListItemPopup::GetRects(HWND hParent, CRect& rcStart, CRect& rcEnd)
{
  // calculate animation rects
  SystemParametersInfo(SPI_GETWORKAREA, 0, &rcEnd, FALSE);
  if (CSettings::IsSmartphone())
    rcEnd.bottom = ::GetSystemMetrics(SM_CYSCREEN);
  // make start rect
  if (pList)
  {
    rcStart = GetRect();
  }
  else
  {
    rcStart = rcEnd;
    rcStart.top = (rcEnd.Height() - height) / 2;
    rcStart.bottom = (rcEnd.Height() + height) / 2;
  }
}

void CLayoutListItemPopup::GetRects(HWND hParent, int dstHeight, CRect& rcStart, CRect& rcEnd, int& headerHeight)
{
  GetRects(hParent, rcStart, rcEnd);
  // check if list is less than screen
  if (dstHeight + headerHeight < rcEnd.Height())
  {
    rcEnd.top += (rcEnd.Height() - dstHeight - headerHeight) / 2;
    rcEnd.bottom = rcEnd.top + dstHeight + headerHeight;
  }
  else
  {
    headerHeight = 0;
  }
}

bool CLayoutListItemInt::Load(CBaseReader& r)
{
  if (!CLayoutListItem::Load(r))
    return false;

  CString val;
  if (!r.ReadPair(TEXT("Min"), val))
    return false;
  m_min = ::_ttoi(val);
  if (!r.ReadPair(TEXT("Max"), val))
    return false;
  m_max = ::_ttoi(val);

  return true;
}

void CLayoutListItemInt::Draw(HDC hdc, const RECT& rc) const
{
  DrawBackground(hdc, rc);

  CRect rctxt = rc;
  rctxt.right = rctxt.left + rctxt.Width() * 2 / 3;
  DrawText(hdc, rctxt, m_text, DT_DEFAULT, CTheme::fntLayoutLbl, CTheme::clrLayoutLbl, CTheme::clrLayoutLblSel);
  rctxt.left = rctxt.right;
  rctxt.right = rc.right - CTheme::iListItemIndent*2;
  DrawText(hdc, rctxt, m_svalue, DT_RIGHT | DT_VCENTER | DT_SINGLELINE, CTheme::fntLayoutInt);
}

bool CLayoutListItemInt::OnKeyDown(HWND hParent, int vKey)
{
  switch (vKey)
  {
  case VK_T0:
  case VK_T1:
  case VK_T2:
  case VK_T3:
  case VK_T4:
  case VK_T5:
  case VK_T6:
  case VK_T7:
  case VK_T8:
  case VK_T9:
    DoEditDlg(hParent, vKey);
    return true;
  }
  return false;
}

bool CLayoutListItemInt::DoEditDlg(HWND hParent, int vKey)
{
  HWND hParentWnd = ::GetParent(hParent);

  CRect rc = GetRect();
  rc.SetRect(0, 0, rc.Width(), rc.Height());

  CListIntInputDlg dlg(this, rc);
  if (!dlg.Create(hParentWnd, NULL, GetText()))
    return false;

  dlg.SetRange(m_min, m_max);
  dlg.SetText(GetValue());
  dlg.SetStartKey(vKey);

  if (pList)
  {
    pList->EnableWindow(FALSE);
    pList->Redraw();
  }

  int res = dlg.DoModal();

  if (pList)
  {
    pList->EnableWindow(TRUE);
    pList->Redraw();
  }

  if (res == IDOK)
  {
    SetValue(dlg.GetText());
  }

  return true;
}

bool CLayoutListItemCheck::Load(CBaseReader& r)
{
  if (!CLayoutListItem::Load(r))
    return false;

  return true;
}

void CLayoutListItemCheck::Draw(HDC hdc, const RECT& rc) const
{
  CImage img = CTheme::GetImage(m_checked ? timCheckboxSet : timCheckboxUnset);

  DrawBackground(hdc, rc);

  CRect rctxt = rc;
  rctxt.right -= CTheme::iListItemIndent*2 + img.width;
  DrawText(hdc, rctxt, m_text, DT_MULTILINE, CTheme::fntLayoutLbl, CTheme::clrLayoutLbl, CTheme::clrLayoutLblSel);
  
  rctxt.right = rc.right - CTheme::iListItemIndent*2;
  rctxt.left = rctxt.right - img.width;
  rctxt.top += (rctxt.Height() - img.height) / 2;
  rctxt.bottom = rctxt.top + img.height;
  img.Draw(hdc, rctxt);
}

bool CLayoutListItemCheck::DoCheck(HWND hParent)
{
  m_checked = !m_checked;
  pList->RedrawItem(pList->GetItemIdx(this));
  return true;
}

bool CLayoutListItemStrList::Load(CBaseReader& r)
{
  if (!CLayoutListItemPopup::Load(r))
    return false;

  m_options.clear();
  CString val;
  if (!r.ReadPair(TEXT("Options"), val))
    return false;
  
  int curPos = 0;
  CString token = val.Tokenize(TEXT(";"), curPos);
  while (!token.IsEmpty())
  {
    token.Trim();
    m_options.push_back(token);
    token = val.Tokenize(TEXT(";"), curPos);
  }

  if (m_options.size() == 0)
    Logger::LogFmt(lsWarning, TEXT("Wrong options string at line %d: '%s'"), r.GetLine(), val.GetString());

  return m_options.size() > 0;
}

bool CLayoutListItemStrList::DoSelectorDlg(HWND hParent)
{
  HWND hParentWnd = ::GetParent(hParent);

  // create dialog
  CListSelectorDlg dlg;
  if (!dlg.Create(hParentWnd, NULL, LANG("Select")))
    return false;

  // fill list
  for (CStringVector::iterator iter = m_options.begin(); iter != m_options.end(); iter++)
  {
    CSelectorListItem* item = new CSelectorListItem(iter->GetString());
    if (item)
      dlg.GetList()->Add(item);
  }
  dlg.SetSelection(GetValue());

  // calculate animation rects
  CRect rcStart, rcEnd;
  int   header = CTheme::iSelectorListItemSize / 2;
  GetRects(hParent, dlg.GetList()->GetHeight(), rcStart, rcEnd, header);
  dlg.SetHeaderHeight(header);

  if (pList)
  {
    pList->EnableWindow(FALSE);
    pList->Redraw();
  }

  // show dialog
  int res = dlg.DoModal(rcStart, rcEnd, SETTINGS.GetInt(sSelectorShowTime), SETTINGS.GetInt(sSelectorHideTime));

  if (pList)
  {
    pList->EnableWindow(TRUE);
    pList->Redraw();
  }

  if (res == IDOK)
  {
    SetValue(dlg.GetSelection());
  }

  return true;
}

bool CLayoutListItemFileList::Load(CBaseReader& r)
{
  if (!CLayoutListItem::Load(r))
    return false;

  m_options.clear();

  CString val;
  if (!r.ReadPair(TEXT("Mask"), val))
    return false;
  if (val.IsEmpty())
    return false;
  
  CString sFile;
  if (val[0] == TEXT('\\'))
  {
    sFile = val;
  }
  else
  {
    sFile = CSettings::GetAppFolder();
    sFile += val;
  }

  if (!r.ReadPair(TEXT("HideExt"), val))
    return false;
  m_hideExt = val.CompareNoCase(TEXT("yes")) == 0 || val.CompareNoCase(TEXT("y")) == 0;

  WIN32_FIND_DATA fd = {0};
  HANDLE hFind = ::FindFirstFile(sFile, &fd);
  if (hFind == INVALID_HANDLE_VALUE)
  {
    Logger::LogFmt(lsWarning, TEXT("No files found for file list under '%s'"), sFile.GetString());
    return false;
  }

  CString name;
  do
  {
    if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ||
        fd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
      continue;

    FileToText(CString(fd.cFileName), name);
    m_options.push_back(name);
  }
  while(::FindNextFile(hFind, &fd));

  ::FindClose(hFind);

  if (m_options.size() == 0)
    Logger::LogFmt(lsWarning, TEXT("No files found for file list under '%s'"), sFile.GetString());

  return m_options.size() > 0;
}

void CLayoutListItemFileList::FileToText(const CString& file, CString& text)
{
  if (m_hideExt)
  {
    int ext = file.ReverseFind(TEXT('.'));
    if (ext >= 0)
      text = file.Left(ext);
    else
      text = file;
  }
  else
  {
    text = file;
  }
}

bool CLayoutListItemFile::Load(CBaseReader& r)
{
  if (!CLayoutListItemPopup::Load(r))
    return false;

  m_filters.clear();

  CString val;
  if (!r.ReadPair(TEXT("Filter"), val))
    return false;

  int curPos = 0;
  CString token = val.Tokenize(TEXT(";"), curPos);
  while (!token.IsEmpty())
  {
    token.Trim();
    m_filters.push_back(token);
    token = val.Tokenize(TEXT(";"), curPos);
  }

  if (m_filters.size() == 0)
    Logger::LogFmt(lsWarning, TEXT("Wrong filter string at line %d: '%s'"), r.GetLine(), val.GetString());

  if (!r.ReadPair(TEXT("AllowRelative"), val))
    return false;
  m_allowRelative = val.CompareNoCase(TEXT("yes")) == 0 || val.CompareNoCase(TEXT("y")) == 0;

  return m_filters.size() > 0;
}

bool CLayoutListItemFile::DoSelectorDlg(HWND hParent)
{
  HWND hParentWnd = ::GetParent(hParent);

  // create dialog
  CString sFolder;
  int fname = GetValue().ReverseFind(TEXT('\\'));
  if (fname >= 0)
    sFolder = GetValue().Left(fname);
  else
    sFolder = CSettings::GetAppFolder();
  CPickFileData pickData(sFolder);
  pickData.allowedExts = m_filters;
  CPickFileDlg dlg(pickData);
  if (!dlg.Create(hParentWnd, NULL, LANG("Select File")))
    return false;

  // calculate animation rects
  CRect rcStart, rcEnd;
  GetRects(hParent, rcStart, rcEnd);

  // show dialog
  int res = dlg.DoModal(rcStart, rcEnd, SETTINGS.GetInt(sSelectorShowTime), SETTINGS.GetInt(sSelectorHideTime));

  if (res == IDOK)
  {
    SetValue(dlg.GetSelection());
  }

  return true;
}

bool CLayoutListItemFolder::Load(CBaseReader& r)
{
  if (!CLayoutListItemPopup::Load(r))
    return false;

  CString val;
  if (!r.ReadPair(TEXT("AllowRelative"), val))
    return false;
  m_allowRelative = val.CompareNoCase(TEXT("yes")) == 0 || val.CompareNoCase(TEXT("y")) == 0;

  return true;
}

bool CLayoutListItemFolder::DoSelectorDlg(HWND hParent)
{
  HWND hParentWnd = ::GetParent(hParent);

  // create dialog
  CString sFolder;
  int fname = GetValue().ReverseFind(TEXT('\\'));
  if (fname >= 0)
    sFolder = GetValue().Left(fname);
  else
    sFolder = GetValue();
  CPickFolderData pickData(sFolder);
  CPickFileDlg dlg(pickData);
  if (!dlg.Create(hParentWnd, NULL, LANG("Select Folder")))
    return false;

  // calculate animation rects
  CRect rcStart, rcEnd;
  GetRects(hParent, rcStart, rcEnd);

  // show dialog
  int res = dlg.DoModal(rcStart, rcEnd, SETTINGS.GetInt(sSelectorShowTime), SETTINGS.GetInt(sSelectorHideTime));

  if (res == IDOK)
  {
    SetValue(dlg.GetSelection());
  }

  return true;
}

bool CLayoutListItemEmailAcc::DoSelectorDlg(HWND hParent)
{
  HWND hParentWnd = ::GetParent(hParent);

  // create dialog
  CListSelectorDlg dlg;
  if (!dlg.Create(hParentWnd, NULL, LANG("Select Account")))
    return false;

  // fill list
  CStringVector accs;
  if (!CUtil::EnumEmailAccounts(accs))
    return false;

  for (CStringVector::iterator iter = accs.begin(); iter != accs.end(); iter++)
  {
    CSelectorListItem* item = new CSelectorListItem(iter->GetString());
    if (item)
      dlg.GetList()->Add(item);
  }
  dlg.SetSelection(GetValue());

  // calculate animation rects
  CRect rcStart, rcEnd;
  int   header = CTheme::iSelectorListItemSize / 2;
  GetRects(hParent, dlg.GetList()->GetHeight(), rcStart, rcEnd, header);
  dlg.SetHeaderHeight(header);

  if (pList)
  {
    pList->EnableWindow(FALSE);
    pList->Redraw();
  }

  // show dialog
  int res = dlg.DoModal(rcStart, rcEnd, SETTINGS.GetInt(sSelectorShowTime), SETTINGS.GetInt(sSelectorHideTime));

  if (pList)
  {
    pList->EnableWindow(TRUE);
    pList->Redraw();
  }

  if (res == IDOK)
  {
    SetValue(dlg.GetSelection());
  }

  return true;
}

void CLayoutListItemColor::Draw(HDC hdc, const RECT& rc) const
{
  DrawBackground(hdc, rc);

  CRect rctxt = rc;
  rctxt.right = rctxt.left + rctxt.Width() * 2 / 3;
  DrawText(hdc, rctxt, m_text, DT_DEFAULT, CTheme::fntLayoutLbl, CTheme::clrLayoutLbl, CTheme::clrLayoutLblSel);

  rctxt.left = rctxt.right + CTheme::iListItemIndent;
  rctxt.right = rc.right - CTheme::iListItemIndent;
  rctxt.top += CTheme::iListItemIndent;
  rctxt.bottom -= CTheme::iListItemIndent;
  FillRect(hdc, &rctxt, m_brush);
}

bool CLayoutListItemColor::DoSelectorDlg(HWND hParent)
{
  HWND hParentWnd = ::GetParent(hParent);

  // create dialog
  CColorDialog dlg(m_color, 0, hParentWnd);

  int res = dlg.DoModal(hParentWnd);

  if (res == IDOK)
  {
    CString sColor = CUtil::MakeColor(dlg.GetColor());
    SetValue(sColor);
  }

  return true;
}